#include "stm32f10x.h" 

/*接口分配*/
#define CTRL_UP GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8)//摇杆上
#define CTRL_DOWN GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14)//摇杆下
#define CTRL_RIGHT GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15)//摇杆右
#define CTRL_LEFT GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)//摇杆左
#define CTRL_STOP GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13)//摇杆中
#define KEY_DELETE GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2)//删除预置点
#define KEY_RUN GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)//前往预置点
#define KEY_SET GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)//设置预置点
#define ID_1 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4)//地址位1
#define ID_2 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5)//地址位2
#define ID_3 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)//地址位3
#define ID_4 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7)//地址位4
#define ID_5 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)//地址位5
#define ID_6 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)//地址位6
#define ID_7 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)//地址位7
#define ID_8 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)//地址位8
#define TURN_1 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15)//预制点位1
#define TURN_2 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3)//预制点位2
#define TURN_3 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4)//预制点位3
#define TURN_4 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5)//预制点位4
#define TURN_5 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_6)//预制点位5
#define TURN_6 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7)//预制点位6
#define TURN_7 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8)//预制点位7
#define TURN_8 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9)//预制点位8

/*变量定义*/
uint8_t SerialTX[7] = {0xff,0x00,0x00,0x00,0x00,0x00,0x00};//发送的数组

/**
  * 函    数：微秒级延时
  * 参    数：xus 延时时长，范围：0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;//设置定时器重装值
	SysTick->VAL = 0x00;//清空当前计数值
	SysTick->CTRL = 0x00000005;//设置时钟源为HCLK，启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}

/**
  * 函    数：毫秒级延时
  * 参    数：xms 延时时长，范围：0~4294967295
  * 返 回 值：无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}

/**
  * 函    数：串口初始化
  * 参    数：无
  * 返 回 值：无
  */
void Serial_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//开启USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//将PA9引脚初始化为复用推挽输出
	
	/*USART初始化*/
	USART_InitTypeDef USART_InitStructure;//定义结构体变量
	USART_InitStructure.USART_BaudRate = 9600;//波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//硬件流控制，不需要
	USART_InitStructure.USART_Mode = USART_Mode_Tx;//模式，选择为发送模式
	USART_InitStructure.USART_Parity = USART_Parity_No;//奇偶校验，不需要
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位，选择1位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长，选择8位
	USART_Init(USART1, &USART_InitStructure);//将结构体变量交给USART_Init，配置USART1
	
	/*USART使能*/
	USART_Cmd(USART1, ENABLE);//使能USART1，串口开始运行
}

/**
  * 函    数：串口发送一个字节
  * 参    数：Byte 要发送的一个字节
  * 返 回 值：无
  */
void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);		//将字节数据写入数据寄存器，写入后USART自动生成时序波形
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	//等待发送完成
}

/**
  * 函    数：串口发送一个数组
  * 参    数：Array 要发送数组的首地址
  * 参    数：Length 要发送数组的长度
  * 返 回 值：无
  */
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)//遍历数组
	{
		Serial_SendByte(Array[i]);//依次调用Serial_SendByte发送每个字节数据
	}
}

/**
  * 函    数：地址位读取
  * 参    数：无
  * 返 回 值：地址位
  */
uint8_t ID(void)
{
	uint8_t read = 0x00;
	if(ID_1 ==0)read=read+0x80;//读取写入1位
	if(ID_2 ==0)read=read+0x40;//读取写入2位
	if(ID_3 ==0)read=read+0x20;//读取写入3位
	if(ID_4 ==0)read=read+0x10;//读取写入4位
	if(ID_5 ==0)read=read+0x08;//读取写入5位
	if(ID_6 ==0)read=read+0x04;//读取写入6位
	if(ID_7 ==0)read=read+0x02;//读取写入7位
	if(ID_8 ==0)read=read+0x01;//读取写入8位
	return read;//返回
}

/**
  * 函    数：预制点位读取
  * 参    数：无
  * 返 回 值：预制点位
  */
uint8_t TURN(void)
{
	uint8_t read = 0x00;
	if(TURN_8 ==0)read=read+0x80;//读取写入1位
	if(TURN_7 ==0)read=read+0x40;//读取写入2位
	if(TURN_6 ==0)read=read+0x20;//读取写入3位
	if(TURN_5 ==0)read=read+0x10;//读取写入4位
	if(TURN_4 ==0)read=read+0x08;//读取写入5位
	if(TURN_3 ==0)read=read+0x04;//读取写入6位
	if(TURN_2 ==0)read=read+0x02;//读取写入7位
	if(TURN_1 ==0)read=read+0x01;//读取写入8位
	return read;//返回
}

/**
  * 函    数：停止命令发送
  * 参    数：无
  * 返 回 值：无
  */
void STOPIN(void)
{
	SerialTX[3]=0x00;//清空操作位
	SerialTX[4]=0x00;//清空数据位1
	SerialTX[5]=0x00;//清空数据位1
	SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
	Serial_SendArray(SerialTX, 7);//发送数据
}

/**
  * 函    数：主函数
  * 参    数：无
  * 返 回 值：无
  */
int main(void)
{
	/*串口初始化*/
	Serial_Init();//串口初始化
	/*接口初始化*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启GPIOB的时钟
	/*接口结构体*/
	GPIO_InitTypeDef GPIO_InitStructure;//创建结构体	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//设置上拉输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//选择开启频率
	/*GPIOB初始化*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 |
																GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | 
																GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;//选择开启端口
	GPIO_Init(GPIOB, &GPIO_InitStructure);//GPIOB初始化
	/*GPIOA初始化*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | 
																GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_15;//选择开启端口
	GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIOA初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//PB3服用设置
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//PB3服用设置
	/*主循环*/ 
	while (1)
	{
		/*识别地址位*/
		SerialTX[1]=ID();		
		/*摇杆上识别*/
		if(CTRL_UP==0)
		{
			while(CTRL_UP==0)//等待摇杆释放
			{
				SerialTX[3]=0x08;//向上标志位：08
				SerialTX[4]=0x00;//左右转速据位
				SerialTX[5]=0xff;//上下转速据位
				SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
				Serial_SendArray(SerialTX, 7);//发送命令
			}
			STOPIN();//结束运动
		}		
		/*摇杆下识别*/
		if(CTRL_DOWN==0)
		{
			while(CTRL_DOWN==0)//等待摇杆释放
			{
				SerialTX[3]=0x10;//向下标志位：10
				SerialTX[4]=0x00;//左右转速据位
				SerialTX[5]=0xff;//上下转速据位
				SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
				Serial_SendArray(SerialTX, 7);//发送命令
			}
			STOPIN();//结束运动
		}		
		/*摇杆右识别*/
		if(CTRL_RIGHT==0)
		{
			while(CTRL_RIGHT==0)//等待摇杆释放
			{
				SerialTX[3]=0x02;//向右标志位：02
				SerialTX[4]=0xff;//左右转速据位
				SerialTX[5]=0x00;//上下转速据位
				SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
				Serial_SendArray(SerialTX, 7);//发送命令
			}
			STOPIN();//结束运动
		}		
		/*摇杆左识别*/
		if(CTRL_LEFT==0)
		{
			while(CTRL_LEFT==0)//等待摇杆释放
			{
				SerialTX[3]=0x04;//向左标志位：04
				SerialTX[4]=0xff;//左右转速据位
				SerialTX[5]=0x00;//上下转速据位
				SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
				Serial_SendArray(SerialTX, 7);//发送命令
			}
			STOPIN();//结束运动
		}		
		/*摇杆制动*/
		if(CTRL_STOP==0)
		{
			while(CTRL_STOP==0)STOPIN();//等待摇杆释放
		}		
		/*删除按键*/
		if (KEY_DELETE==0)
		{
		Delay_ms(10);//延时消抖
		while (KEY_DELETE==0);	//等待按键松手
		Delay_ms(10);//延时消抖
		STOPIN();//停止当前运动
		SerialTX[3]=0x05;//删除标志位：03
		SerialTX[4]=0x00;//无数据位
		SerialTX[5]=TURN();//读取预制点位
		SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
		Serial_SendArray(SerialTX, 7);//发送命令
		}		
		/*设置按键*/
		if (KEY_SET==0)
		{
		Delay_ms(10);//延时消抖
		while (KEY_SET==0);	//等待按键松手
		Delay_ms(10);//延时消抖
		STOPIN();//停止当前运动
		SerialTX[3]=0x03;//设置标志位：03
		SerialTX[4]=0x00;//无数据位
		SerialTX[5]=TURN();//读取预制点位
		SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
		Serial_SendArray(SerialTX, 7);//发送命令
		}		
		/*转至按键*/
		if (KEY_RUN==0)
		{
		Delay_ms(10);//延时消抖
		while (KEY_RUN==0);	//等待按键松手
		Delay_ms(10);//延时消抖
		STOPIN();//停止当前运动
		SerialTX[3]=0x07;//转至标志位：07
		SerialTX[4]=0x00;//无数据位
		SerialTX[5]=TURN();//读取预制点位
		SerialTX[6]=(SerialTX[1]+SerialTX[2]+SerialTX[3]+SerialTX[4]+SerialTX[5])%0x0100;//计算检验位
		Serial_SendArray(SerialTX, 7);//发送命令
		}			
	}
}
